/**
 * validatebox - jQuery xui
 *
 * Licensed under the GPL: http://www.gnu.org/licenses/gpl.txt
 *
 * Copyright 2013 xjb [ beymy.en@gmail.com ]
 *
 */
(function($) {
    /**
     * 构建
     */
    function build(target) {
        $(target).addClass('validatebox-text');
    }

    /**
     * 销毁box
     */
    function destroyBox(target) {
        var tip = $.data(target, 'validatebox').tip;
        if (tip) {
            tip.remove();
        }
        $(target).unbind('.validatebox');
        $(target).removeData('validatebox');
    }

    /**
     * 绑定事件
     */
    function bindEvents(target) {
        var box = $(target);
        var state = $.data(target, 'validatebox');

        if (state.timer) {
            clearTimeout(state.timer);
            state.timer = undefined;
        }
        box.unbind('.validatebox');
        if (state.options.novalidate) {
            return;
        }
        box.bind('focus.validatebox', function() {
            state.validating = true;
            state.value = undefined;
            (function() {
                if (state.validating) {
                    if (state.value != box.val()) {
                        state.value = box.val();
                        if (state.timer) {
                            clearTimeout(state.timer);
                        }
                        state.timer = setTimeout(function() {
                            validate(target);
                        }, state.options.delay);
                    }
                    setTimeout(arguments.callee, 200);
                }
            })();
        }).bind('blur.validatebox', function() {
            if (state.timer) {
                clearTimeout(state.timer);
                state.timer = undefined;
            }
            state.validating = false;
            validate(this);
        }).bind('mouseover.validatebox', function() {
            if (box.hasClass('validatebox-invalid')) {
                showTip(target);
            }
        }).bind('mouseout.validatebox', function() {
            if (!state.validating) {
                hideTip(target);
            }
        });
    }

    /**
     * 显示提示信息
     */
    function showTip(target) {
        var box = $(target);
        var msg = $.data(target, 'validatebox').message;
        var tip = $.data(target, 'validatebox').tip;
        if (!tip) {
            tip = $(
                '<div class="validatebox-tip">' +
                '<span class="validatebox-tip-content">' +
                '</span>' +
                '<span class="validatebox-tip-arrow-outer">' +
                '</span>' +
                '<span class="validatebox-tip-arrow">' +
                '</span>' +
                '</div>'
            ).appendTo('body');
            $.data(target, 'validatebox').tip = tip;
        }
        tip.find('.validatebox-tip-content').html(msg);
        tip.css({
            display: 'block',
            left: box.offset().left + box.outerWidth() + $('.validatebox-tip-arrow-outer', tip).outerWidth(),
            top: box.offset().top - (tip.outerHeight() - box.outerHeight()) / 2
        })
    }

    /**
     * 隐藏提示信息
     */
    function hideTip(target) {
        var tip = $.data(target, 'validatebox').tip;
        if (tip) {
            tip.css({
                display: 'none'
            })
        }
    }

    /**
     * 验证
     */
    function validate(target) {
        var state = $.data(target, 'validatebox');
        var opts = state.options;
        var tip = state.tip;
        var box = $(target);
        var value = box.val();

        function setTipMessage(msg) {
            $.data(target, 'validatebox').message = msg;
        }

        if (opts.novalidate || box.is(":disabled")) {
            return true;
        }

        if (opts.required) {
            if (value === '' || value === null) {
                box.addClass('validatebox-invalid');
                setTipMessage(opts.missingMessage);
                showTip(target);
                return false;
            }
        }
        if (opts.validType) {
            var result = /([a-zA-Z_]+)(.*)/.exec(opts.validType);
            var rule = opts.rules[result[1]];
            if (value && rule) {
                var param = eval(result[2]);
                if (!rule['validator'](value, param)) {
                    box.addClass('validatebox-invalid');

                    var message = rule['message'];
                    if (param) {
                        for (var i = 0; i < param.length; i++) {
                            message = message.replace(new RegExp("\\{" + i + "\\}", "g"), param[i]);
                        }
                    }
                    setTipMessage(opts.invalidMessage || message);
                    showTip(target);
                    return false;
                }
            }
        }

        box.removeClass('validatebox-invalid');
        hideTip(target);
        return true;
    }

    /**
     * 是否禁用验证
     */
    function disableValidate(target, disable) {
        var opts = $.data(target, "validatebox").options;
        if (disable != undefined) {
            opts.novalidate = disable;
        }
        if (opts.novalidate) {
            $(target).removeClass("validatebox-invalid");
            hideTip(target);
        }
        bindEvents(target);
    };

    $.fn.validatebox = function(options, param) {
        if (typeof options == 'string') {
            return $.fn.validatebox.methods[options](this, param);
        }

        options = options || {};
        return this.each(function() {
            var state = $.data(this, 'validatebox');
            if (state) {
                $.extend(state.options, options);
            } else {
                $.data(this, 'validatebox', {
                    options: $.extend({}, $.fn.validatebox.defaults, $.fn.validatebox.parseOptions(this), options)
                });
                build(this);
            }

            bindEvents(this);
        });
    };

    $.fn.validatebox.parseOptions = function(target) {
        return $.extend({}, $.parser.parseOptions(target, [
            'validType', 'missingMessage', 'invalidMessage', {
                required: 'boolean',
                novalidate: 'boolean',
                delay: 'number'
            }
        ]));
    };

    $.fn.validatebox.methods = {
        destroy: function(jq) {
            return jq.each(function() {
                destroyBox(this);
            });
        },
        validate: function(jq) {
            return jq.each(function() {
                validate(this);
            });
        },
        isValid: function(jq) {
            return validate(this[0]);
        },
        enableValidation: function(jq) {
            return jq.each(function() {
                disableValidate(this, false);
            });
        },
        disableValidation: function(jq) {
            return jq.each(function() {
                disableValidate(this, true);
            });
        }
    };

    $.fn.validatebox.defaults = {
        required: false,
        validType: null,
        delay: 200,
        missingMessage: '该输入项为必输项',
        invalidMessage: null,
        novalidate: false,
        rules: {
            email: {
                validator: function(value) {
                    return /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value);
                },
                message: '请输入有效的电子邮件地址'
            },
            url: {
                validator: function(value) {
                    return /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
                },
                message: '请输入有效的URL地址'
            },
            length: {
                validator: function(value, param) {
                    var len = $.trim(value).length;
                    return len >= param[0] && len <= param[1]
                },
                message: '输入内容长度必须介于{0}和{1}之间'
            }
        }
    };
})(jQuery);
